#include "cubemap.h"
#include "ext/stb_image.h"

namespace teflon
{
	Cubemap::Cubemap()
	{
		glGenTextures(1, &texture_id);
	}

	Cubemap::~Cubemap()
	{
		glDeleteTextures(1, &texture_id);
	}

	void Cubemap::Load(const std::vector<std::string>& filepaths)
	{
		glBindTexture(GL_TEXTURE_CUBE_MAP, texture_id);

		// set texture parameters
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);

		// load faces
		load_face(filepaths[0], GL_TEXTURE_CUBE_MAP_POSITIVE_X);
		load_face(filepaths[1], GL_TEXTURE_CUBE_MAP_NEGATIVE_X);
		load_face(filepaths[2], GL_TEXTURE_CUBE_MAP_POSITIVE_Y);
		load_face(filepaths[3], GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);
		load_face(filepaths[4], GL_TEXTURE_CUBE_MAP_POSITIVE_Z);
		load_face(filepaths[5], GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
	}

	void Cubemap::Bind(uint32_t texture_slot) const
	{
		glActiveTexture(GL_TEXTURE0 + texture_slot);
		glBindTexture(GL_TEXTURE_CUBE_MAP, texture_id);
	}

	void Cubemap::Unbind() const
	{
		glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
	}

    bool Cubemap::load_face(const std::string& filepath, GLuint target)
    {
		// glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
		stbi_set_flip_vertically_on_load(false);

		int x, y, n;
		int force_channels = 4;
		unsigned char* image_data = stbi_load(filepath.c_str(), &x, &y, &n, force_channels);
		if (!image_data) {
			fprintf(stderr, "ERROR: could not load %s\n", filepath.c_str());
			return false;
		}
		// non-power-of-2 dimensions check
		if ((x & (x - 1)) != 0 || (y & (y - 1)) != 0) { fprintf(stderr, "WARNING: image %s is not power-of-2 dimensions\n", filepath.c_str()); }

		// copy image data into 'target' side of cube map
		glTexImage2D(target, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
		free(image_data);
		return true;
    }
}
